package com.jingdianjichi.auth.domain.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.gson.Gson;
import com.jindianjichi.common.enums.IsDeletedFlagEnum;
import com.jindianjichi.common.enums.UserStatusEnum;
import com.jingdianchi.common.constant.AuthConstants;
import com.jingdianjichi.auth.domain.convert.AuthUserBOConverter;
import com.jingdianjichi.auth.domain.entity.AuthUserBO;
import com.jingdianjichi.auth.domain.redis.RedisUtil;
import com.jingdianjichi.auth.domain.service.AuthUserDomainService;
import com.jingdianjichi.auth.infra.basic.entity.*;
import com.jingdianjichi.auth.infra.basic.service.*;
import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AuthUserDomainServiceImpl implements AuthUserDomainService {

    @Resource
    private AuthUserService authUserService;

    @Resource
    private AuthRoleService authRoleService;

    @Resource
    private AuthUserRoleService authUserRoleService;

    @Resource
    private AuthPermissionService authPermissionService;
    @Resource
    private AuthRolePermissionService authRolePermissionService;

    @Resource
    private RedisUtil redisUtil;

    public static final String LOGIN_PREFIX = "login";


    private String authPermissionPrefix = "auth.permission";


    private String authRolePrefix = "auth.role";
    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean register(AuthUserBO authUserBO) {
        //校验是否存在 存在就直接返回
        AuthUser existAuthUser = new AuthUser();
        existAuthUser.setUserName(authUserBO.getUserName());
        List<AuthUser> authUserList  = authUserService.getByCondition(existAuthUser);
        if(authUserList.size() > 0){
            return true;
        }


        AuthUser authUser=AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        authUser.setStatus(UserStatusEnum.OPEN.getCode());
//        authUser.setPassword(SaSecureUtil.aesEncrypt(authUser.getPassword(),key));
        //rsa非对称加密
/*        HashMap<String, String> keyMap = SaSecureUtil.rsaGenerateKeyPair();
        String publicKey = keyMap.get("public");
        String privateKey = keyMap.get("private");
        //公钥加密 私钥解密
        String psw = SaSecureUtil.rsaEncryptByPublic(publicKey, authUser.getPassword());
        SaSecureUtil.rsaDecryptByPrivate(privateKey,authUser.getPassword());*/
        if(StringUtils.isNotBlank(authUserBO.getPassword())){
            authUser.setPassword(SaSecureUtil.md5BySalt(authUser.getPassword(),"123456"));
        }
        Integer count = authUserService.insert(authUser);

        //给用户关联角色
        AuthRole authRole = new AuthRole();
        authRole.setRoleKey(AuthConstants.NORMAL);
        //查询角色
        AuthRole role = authRoleService.queryByCondition(authRole);
        //关联到用户角色表中
        Long userId = authUser.getId();
        Long roleId = role.getId();

        AuthUserRole authUserRole = new AuthUserRole();
        authUserRole.setUserId(userId);
        authUserRole.setRoleId(roleId);
        authUserRole.setIsDeleted(IsDeletedFlagEnum.NOT_DELETED.getCode());
        authUserRoleService.insert(authUserRole);
        //关联用户角色加入到redis中
        String roleKey = redisUtil.buildKey(authRolePrefix, authUser.getUserName());
        List<AuthRole> roleList = new ArrayList<>();
        roleList.add(role);
        List<String> roleKeyList = roleList.stream().map(AuthRole::getRoleKey).collect(Collectors.toList());
        redisUtil.set(roleKey, new Gson().toJson(roleKeyList));

        //角色权限加入redis
        //1.根据roleId查询角色权限关联表 查询到角色的拥有的相关权限
        AuthRolePermission authRolePermission = new AuthRolePermission();
        authRolePermission.setRoleId(roleId);
        List<AuthRolePermission> authRolePermissionList = authRolePermissionService.queryByCondition(authRolePermission);
        List<Long> permissionIdList = authRolePermissionList.stream().map(AuthRolePermission::getPermissionId).collect(Collectors.toList());
        //通过权限id集合查询权限

        List<AuthPermission> permissionList = authPermissionService.queryByIds(permissionIdList);
        //将权限放入到redis中
        List<String> permissionKeyList = permissionList.stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());
        String permissionKey = redisUtil.buildKey(authPermissionPrefix, authUser.getUserName());
        redisUtil.set(permissionKey,new Gson().toJson(permissionKeyList));
        return count > 0;
    }

    @Override
    public Boolean update(AuthUserBO authUserBO) {
        AuthUser authUser=AuthUserBOConverter.INSTANCE.convertBOToEntity(authUserBO);
        Integer count = authUserService.update(authUser);
        return count > 0;
    }

    @Override
    public Boolean delete(AuthUserBO authUserBO) {
        return null;
    }

    @Override
    public AuthUserBO getUserInfo(AuthUserBO authUserBO) {
        AuthUser authUser = new AuthUser();
        authUser.setUserName(authUserBO.getUserName());
        List<AuthUser> authUserList = authUserService.getByCondition(authUser);
        if(CollectionUtils.isEmpty(authUserList)){
            return new AuthUserBO();
        }
        AuthUser userInfo = authUserList.get(0);
        AuthUserBO userInfoBO = AuthUserBOConverter.INSTANCE.convertEntityToBO(userInfo);
        return userInfoBO;
    }

    @Override
    public List<AuthUserBO> listUserInfoByIds(List<String> ids) {
        return Collections.emptyList();
    }

    @Override
    public SaTokenInfo doLogin(String validCode) {
        String codeKey = redisUtil.buildKey(LOGIN_PREFIX, validCode);
        String openId = redisUtil.get(codeKey);
        if(StringUtils.isBlank(openId)){
            return null;
        }
        AuthUserBO authUser = new AuthUserBO();
        authUser.setUserName(openId);
        authUser.setStatus(UserStatusEnum.OPEN.getCode());
        this.register(authUser);
        StpUtil.login(openId);
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        return tokenInfo;
    }
}
